﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UnityEngine;

namespace TC
{
    public class Actor : MonoBehaviour
    {
        public List<Component> components = new List<Component>();

        private void Awake()
        {
            //_prepareBT();

            _prepareFlow();
        }

        private void OnEnable()
        {
            foreach (var i in components)
            {
                i.OnEnable();
            }
        }

        private void Update()
        {
            foreach (var i in components)
            {
                i.OnUpdate();
            }
        }

        private void OnDisable()
        {
            foreach (var i in components)
            {
                i.OnDisable();
            }
        }

        private void _prepareFlow()
        {
            KeyComponent kc = new KeyComponent();
            kc.graph = new FlowGraph(new Context(), new Flow());

            KeyDownEvent n0 = kc.graph.AddNode<KeyDownEvent>();
            n0.keyCode = KeyCode.Space;
            Print n1 = kc.graph.AddNode<Print>();

            kc.graph.AddConnection(n0.flowOut, n1.flowIn);
            kc.graph.AddConnection(n0.keyCodeOut, n1.valueIns[0]);

            CreateCube n2 = kc.graph.AddNode<CreateCube>();
            kc.graph.AddConnection(n1.flowOut, n2.flowIn);

            ConstFloat f0 = kc.graph.AddNode<ConstFloat>();
            f0.value = 10;

            Random n3 = kc.graph.AddNode<Random>();
            Mul m0 = kc.graph.AddNode<Mul>();
            kc.graph.AddConnection(n3.insideUnitSphere, m0.vecIn);
            kc.graph.AddConnection(f0.fOut, m0.ts);
            kc.graph.AddConnection(m0.vecOut, n2.posIn);

            ConstVector3 n4 = kc.graph.AddNode<ConstVector3>();
            n4.value = new Vector3(5, 5, 5);
            Mul m1 = kc.graph.AddNode<Mul>();
            kc.graph.AddConnection(n4.vecOut, m1.vecIn);
            Random f1 = kc.graph.AddNode<Random>();
            kc.graph.AddConnection(f1.value, m1.ts);
            kc.graph.AddConnection(m1.vecOut, n2.scaleIn);

            //RandomVector3 n5 = kc.graph.AddNode<RandomVector3>();

            ReflectStaticProperty n5 = new ReflectStaticProperty();
            n5.classType = typeof(UnityEngine.Random);
            n5.property = n5.classType.GetProperty("insideUnitSphere");
            kc.graph.AddNode(n5);
            Mul m2 = kc.graph.AddNode<Mul>();
            kc.graph.AddConnection(n5.valueOut, m2.vecIn);
            kc.graph.AddConnection(f0.fOut, m2.ts);
            kc.graph.AddConnection(m2.vecOut, n2.rotateIn);

            components.Add(kc);
        }

        private void _prepareBT()
        {
            //BTComponent bt = new BTComponent();
            //bt.graph = new BTGraph();
        }
    }
    
    public abstract class Component
    {
        protected Actor actor;

        public virtual void OnCreate() { }
        public virtual void OnEnable() { }
        public virtual void OnUpdate() { }
        public virtual void OnDisable() { }
        public virtual void OnDestroy() { }
    }

    public class KeyComponent : Component
    {
        public FlowGraph graph;

        private Type eventType = typeof(KeyDownEvent);

        public override void OnUpdate()
        {
            base.OnUpdate();

            if (Input.anyKeyDown)
            {
                graph.Call<KeyDownEvent>();
            }
        }
    }
    
    public class BTComponent : Component
    {
        public BTGraph graph;

        public override void OnEnable()
        {
            base.OnEnable();

            graph.Start();
        }

        public override void OnUpdate()
        {
            base.OnUpdate();

            graph.OnUpdate();
        }

        public override void OnDisable()
        {
            base.OnDisable();

            graph.Stop();
        }
    }

    public class Binder
    {
        public void func()
        {
            Type type = typeof(GameObject);

            FieldInfo[] fields = type.GetFields(BindingFlags.Public);

            StringBuilder code = new StringBuilder();
            code.Append("namespace TC.Gen");
            code.Append("\n{");
            code.Append("\n\tpublic class ");
            code.Append(type.Name);
            code.Append("_Bind");
            code.Append("\n\t{");

            code.Append("\n\t}");
            code.Append("}\n");
        }
    }

    public class ActorObject
    {
        public int id;
        public string name;

        public GameObject[] child;

        public Transform tran { get; set; }

        public Component GetComponent(string name)
        {
            return null;
        }

        public T GetComponent<T>(string name)
        {
            return default;
        }

        public void Look(int i, float j)
        {
        }

        public static void Create()
        {
        }
    }

    public class GameObject_Bind : VariableNode
    {
        public ValueInput<GameObject> go;

        public override void OnCreate()
        {
            base.OnCreate();

            go = new ValueInput<GameObject>(this, "gameObject");
        }

        public void clear()
        {
            inputPorts.Clear();
            outputPorts.Clear();
        }

        /// <summary>
        /// 属性
        /// </summary>
        public void init_name()
        {
            this.AddPort(go);
            this.AddValueOutPort<string>("name", () => { return go.name; });
        }

        /// <summary>
        /// 函数
        /// </summary>
        public void init_GetComponent()
        {
            this.AddPort(go);
            ValueInput<string> vi = this.AddValueInPort<string>("name");//输入参数
            this.AddValueOutPort("comp", () => { return go.Value.GetComponent(vi.Value); });
        }

        /// <summary>
        /// 数组
        /// </summary>
        public void init_childs()
        {
            this.AddPort(go);
            this.AddValueOutPort("childs", () => { return go.Value.scene; });
        }

        public void init_property()
        {

        }
    }
}
